#include "FaceDiscern.h"

FaceDiscern::FaceDiscern()
{
    base_dir = FACE_BASE_DIR;
    index_filename = base_dir + FACE_CSV;
    recognizer_filename = base_dir + FACE_XML;
    face_detector_filename = base_dir + FACE_ALT;
    model = LBPHFaceRecognizer::create(1, 8, 8, 8, 50.0);
    model->read(recognizer_filename);
}

FaceDiscern::~FaceDiscern()
{

}

Ptr<LBPHFaceRecognizer> FaceDiscern::getModel()
{
    return model;
}

bool FaceDiscern::face_train(string& filelist_txt) {//模型训练
    //定义必要的变量,参数：（文件名字符串，模式（in/out））,其他参数默认
    vector<Mat> mats;
    vector<int> labels;
    cout << filelist_txt << endl;
    ifstream file(filelist_txt, ifstream::in);
    if (!file.is_open()) {//当不是被打开
        qWarning("file is not open!");
        return false;//返回false
    }else{
        qWarning("file is open!");
    }
    //读取文件每一行
    string lines;//定义行字符串变量
    while (1) {//当不是EOF时，继续读取
        //读取一行,参数：（文件流，字符串变量）
        getline(file,lines);
        if(file.eof()) break;
        //定义字符串流
        stringstream line_stream(lines);
        //读取图片路径
        string path;//定义路径变量
        getline(line_stream,path,',');//读取路径，用逗号分隔符为结束
        cout << path << endl;
        //读取标签
        string label;//定义标签变量
        getline(line_stream,label);//读取其余部分，标签部分
        cout << label << endl;
        //读取路径指定的图片（彩色）
        Mat img = imread(path,IMREAD_GRAYSCALE);//读取灰度图
        //调整图片为128*128,参数：（原图矩阵，目标图矩阵，图尺寸，x比例，y比例，插值类型）
        resize(img,img,Size(128,128),0,0,INTER_LINEAR);
        //存入向量
        mats.push_back(img.clone());//存入矩阵向量
        labels.push_back(atoi(label.c_str()));//存入标签向量
    }
    //判读向量状态
    if (mats.empty()||labels.empty()||mats.size()!=labels.size()) {//当向量为空，或两向量个数不相等时，返回假
        return false;//返回false
    }
    //判断参数
    if (mats.empty() || labels.empty() || mats.size()!=labels.size()) {//当向量为空，或尺寸不相等时，返回假
        return false;//返回false
    }
    qWarning("Start trainning");
    //训练模型
    this->model->train(mats,labels);//参数:(矩阵向量，标签向量)
    //保存模型
    qWarning("trainning success,save the model");
    this->model->save(recognizer_filename);//参数：（文件名字符串）
    return true;//返回真
}

bool FaceDiscern::update_face(vector<Mat>& mats, vector<int>&labels) {//更新训练模型
    //判断参数
    if (mats.empty() || labels.empty() || mats.size() != labels.size()) {//当向量为空，或尺寸不相等时，返回假
        return false;//返回false
    }
    //更新训练模型
    this->model->update(mats, labels);//参数:(矩阵向量，标签向量)
    //保存模型
    this->model->save(recognizer_filename);//参数：（文件名字符串）
    return true;//返回真
}

vector<int> FaceDiscern::face_predict(vector<Mat>& testImages){//face预测函数
    //定义结果向量
    vector<int> result;
    //判断向量合法性
    if (testImages.empty()) {//当向量为空时
        qWarning("no input image");
        return result;//返回空的结果向量
    }

    if(this->model->empty()){//当模型为空
        qWarning("face model load fault!");
        return result;//返回空的结果向量
    }
    //定义必要的变量
    int label = -1;//标签变量
    double confidence_distance = 0;//置信值
    //循环遍历矩阵向量
    for (long unsigned int i = 0; i < testImages.size();i++) {
        //预测分类结果,参数:(图矩阵，标签变量，置信概率变量)
        this->model->predict(testImages[i],label, confidence_distance);
        if (confidence_distance>80) {//当置信距离大于80时，给标签-1表示未知
            label = -1;//标签给-1
        }
        //存入向量
        result.push_back(label);
    }
    return result;//返回向量
}

bool FaceDiscern::face_find(Mat& frame_input, vector<Mat>& testImages)
{
    cout << "******************Try to find face_find xml*****************" << endl;
    cout << face_detector_filename << endl;
    ifstream file(face_detector_filename, ifstream::in);
    if (!file.is_open()) {//当不被打开
        qWarning("face_find file is not open!");
        cout <<"/-----------------------------------------------------------/" << endl;
        return false;//返回false
    }else{
        qWarning("file is open!");
    }

    CascadeClassifier cascade_face(face_detector_filename);//定义级联分类器
    vector<Rect> face_rects;
    Rect rect;

    cascade_face.detectMultiScale(frame_input, face_rects, 1.09, 1, 0, Size(200, 200), Size(400, 400));//识别脸
    if (face_rects.empty()) {//当向量为空时
        return false;
    }
    //保存脸和绘制脸位置
    for (long unsigned int i = 0; i < face_rects.size(); i++) {//循环脸向量位置
        //获得人脸部分矩形
        rect = face_rects[i];
        //发现脸并存入矩阵向量
        Mat dst;//定义新图
        //调整脸图片大小，128*128,参数：（原图，目标图，尺寸，x比例，y比例，线性插值类型）
        resize(frame_input(rect), dst, Size(128, 128), 0, 0, INTER_LINEAR);
        cvtColor(dst, dst, COLOR_BGR2GRAY);
        testImages.push_back(dst.clone());//添加到脸向量,需要clone()操作
        //绘制识别脸位置矩形,参数：（图，矩形变量，颜色，线宽，线型，偏移量）
        rectangle(frame_input, Rect(rect.x,rect.y,rect.width,rect.height),Scalar(255,0,0),1,8,0);
    }
    return true;
}

























